package patternRecognition;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

import fields.FieldMatcher;
import fileProcessing.ParsingException;
import fileProcessing.preprocessorException;

public abstract class PatternQuery {
	
	private File currFile;
	private String source="",date="";
	protected ArrayList<keywordStruct> fieldnameMatches = new ArrayList<keywordStruct>();
	protected ArrayList<String> fieldNamesFound = new ArrayList<String>();
	protected ArrayList<ArrayList<String>> wordsByRow = new ArrayList<ArrayList<String>>();
	private int words=0,lines=0;
	private double statisticalMatch;
	protected ArrayList<String> fields = new ArrayList<String>();
	protected ArrayList<String> data = new ArrayList<String>();
	
	public PatternQuery(File f){
		currFile = f;
	}
	
	public ArrayList<String> getFields(){
		return fields;
	}
	
	public ArrayList<String> getData(){
		return data;
	}
	
	public double getStatisticalMatch(){
		return statisticalMatch;
	}
	
	public String getCollectionSource(){
		return source;
	}
	
	public String getCollectionDate(){
		return date;
	}
	
	public abstract void performAnalysis() throws ParsingException;
	
	
	public int countOf(String s,ArrayList<String> list){
		int count=0;
		if(list.contains(s)){
			for(String temp : list){
				if(temp.equals(s))
					count++;
			}
		}
		return count;
	}
	
	/**
	 * Tokenizes a line as well as removes commas,extra spaces, quotes and apostrophes.
	 * @param line
	 * @return
	 */
	public String[] getTokenizedLine(String line){
		String[] tokens;
		String temp = line;
		temp = temp.replaceAll("=", " ");
		temp = temp.replaceAll(",", " ");
		temp = temp.replaceAll("\\|", " ");
		temp = temp.replaceAll("\"", "");
		temp = temp.replaceAll("'", "");
		temp = temp.replaceAll("\\s+", " ");
		tokens = temp.toLowerCase().split("\\s");
		return tokens;
	}
	
	public String getConditionedLine(String[] line){
		String result = "";
		int i=1;
		for(String word : line){
			if(i<line.length)
				result += word+' ';
			else
				result += word;
		}
		return result;
	}
	
	public class keywordStruct{
		public String word;
		private ArrayList<int[]> position = new ArrayList<int[]>();//to be stored as "x,y";
		public int numberOfOccurrences=0;
		
		public keywordStruct(String s){
			word = s;
		}
		
		public keywordStruct(String s, int col, int row){
			word = s;
			addNewHit(col,row);
		}
		
		public void addNewHit(int x,int y){
			int[] pos = new int[2];
			pos[0] = x;
			pos[1] = y;
			position.add(pos);
			numberOfOccurrences++;
		}
		
		public ArrayList<int[]> getPos(){
			return position;
		}
	}
		
	/**
	 * Attempt to identify vertically listed records by looking for vertical patterns.
	 * @param file
	 * @throws ParsingException 
	 */
	public void analyzeFile() throws ParsingException{
		try {
			BufferedReader file = new BufferedReader(new FileReader(currFile));
			int temp,maxLineSize=0;
			String[] lineTokens;
			String currentLine = file.readLine();
			//read in file
			while(currentLine != null){
				lines++;
				if(lines==1)
					source = currentLine;
				else if(lines==2)
					date = currentLine;
				else{
					lineTokens = getTokenizedLine(currentLine);
					temp = lineTokens.length;
					words+=temp;
					if(temp>maxLineSize)
						maxLineSize = temp;
					ArrayList<String> tokens = new ArrayList<String>(lineTokens.length);
					for(String s : lineTokens){
						tokens.add(s);
					}
					wordsByRow.add(tokens);
				}
				currentLine = file.readLine();
			}
			
			//Run scans on indices to identify key words
			int x=0,y=0;
			boolean hasValue;
			for(ArrayList<String> currentIndex : wordsByRow){
				for(String s : currentIndex){
					if(FieldMatcher.matchesField(s)){
						//System.out.println(s);
						hasValue = false;
						for(Iterator<keywordStruct> structList = fieldnameMatches.iterator();structList.hasNext();){
							keywordStruct nextMatch = structList.next();
							if(nextMatch.word.equalsIgnoreCase(s)){
								nextMatch.addNewHit(x, y);
								hasValue=true;
							}
						}
						if(!hasValue)
							fieldnameMatches.add(new keywordStruct(s,x,y));
					}
					y++;
					}
				x++;
				}
			for(keywordStruct s : fieldnameMatches)
				fieldNamesFound.add(s.word);
			file.close();
		} catch (IOException e) {
			throw new ParsingException("Error reading the file during PatternQuery: "+e.getMessage());
		}
	}
	
	/**
	 * Return the line requested.
	 * @param lineNumber
	 * @throws preprocessorException 
	 */
	protected String seek(int lineNumber) throws ParsingException {
		try{
			BufferedReader newReader = new BufferedReader(new FileReader(currFile));
			String line;
			for(int i=0;i<lineNumber;i++)
				newReader.readLine();
			line = newReader.readLine();
			return line;
		} catch (IOException e){
			throw new ParsingException("Error caught while seeking in structure class.");
		}
	}
	
	protected void printResults(){
		int counter=0,recno=0,pos;	
		for(String d : data){
			pos = counter%fields.size();
			if(pos==0){
				System.out.println("Record: #"+(recno++));
				System.out.println(fields.get(pos)+" "+d);
			}
			else{
				System.out.println(fields.get(pos)+" "+d);
			}
			counter++;
		}
	}
}
